package com.qf.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cache.annotation.CacheDel;
import com.cache.annotation.CacheUsing;
import com.qf.aop.UserLocal;
import com.qf.commons.DateUtil;
import com.qf.coupon.CouponUtil;
import com.qf.coupon.limit.ILimit;
import com.qf.coupon.rule.IRule;
import com.qf.dao.CouponDao;
import com.qf.entity.Coupon;
import com.qf.entity.CouponGet;
import com.qf.entity.PricesParams;
import com.qf.entity.User;
import com.qf.service.CouponGetService;
import com.qf.service.CouponService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * (Coupon)表服务实现类
 *
 * @author makejava
 * @since 2020-10-14 14:33:55
 */
@Service("couponService")
public class CouponServiceImpl extends ServiceImpl<CouponDao, Coupon> implements CouponService {

    @Autowired
    private CouponGetService couponGetService;

    @Autowired
    private CouponDao couponDao;

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 保存优惠券
     * @param entity
     * @return
     */
    @Override
    @CacheDel(key = "'coupons_' + #entity.goStartTime.getTime()")
    public boolean save(Coupon entity) {
        boolean result = super.save(entity);

        //判断当前优惠券是否为抢劵模式
        if (entity.getMethod() == 1) {
            //抢劵,获得开抢时间
            Date startTime = entity.getGoStartTime();
            //计算redis后缀
            SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHH");
            String timeStr = sdf.format(startTime);
            //保存到redis
            redisTemplate.opsForSet().add("qiangjuan_" + timeStr, entity.getId() + "");

            //优惠券的库存，同步到redis中
            redisTemplate.opsForHash().put("coupon_save", "save_" + entity.getId(), entity.getNumber() + "");
        }

        return result;
    }

    /**
     * 领取优惠券
     * @param cid
     * @return
     */
    @Override
    public boolean couponGet(Integer cid, Integer method) {
        Coupon coupon = super.getById(cid);

        if (coupon.getType() == 0) {}

        //领取对象
        CouponGet couponGet = new CouponGet()
                .setUid(UserLocal.getUser().getId())
                .setCid(cid)
                .setGetType(method)
                .setGetTime(new Date())
                .setTimeout(coupon.getType() == 0 ? coupon.getEndTime() : DateUtil.getNextDate(coupon.getDays()));

        return couponGetService.save(couponGet);
    }

    /**
     * 查询优惠券列表 -
     * @return
     */
    @Override
    public List<Coupon> list(Integer method) {

        //获得当前用户
        User user = UserLocal.getUser();

        if (user == null || method == null)
            //未登录
            return super.list(method == null ? null : new QueryWrapper<Coupon>().eq("method", method));
        else
            //已登录
            return couponDao.getCouponListByUser(method, user.getId());
    }

    /**
     * 查询用户的可用优惠券列表 - 订单编译时使用
     * @param pricesParams
     * @return
     */
    @Override
    public List<List<Coupon>> userList(PricesParams pricesParams) {

        //用户信息
        User user = UserLocal.getUser();
        //当前用户领取的所有优惠券
        List<Coupon> couponList = couponDao.getCouponList(user.getId());

        //可用优惠券
        List<Coupon> canUserList = new ArrayList<>();
        //不可用优惠券
        List<Coupon> noCanUserList = new ArrayList<>();

        List<List<Coupon>> resultList = new ArrayList<>();
        resultList.add(canUserList);
        resultList.add(noCanUserList);

        //循环处理这些优惠券
        for (Coupon coupon : couponList) {
            //将coupon的规则、限制 -反射-> 实际的实现对象 -> 判断能否优惠、优惠多少.....
            //{"ruleClass":"com.qf.coupon.rule.impl.ManJianRule","fields":[{"name":"must","value":"1000"},{"name":"jian","value":"2"}]}

            //获得当前优惠券的优惠规则
            IRule rule = CouponUtil.parseDynamicRuleField(coupon);
            //获取当前优惠券的限制对象
            ILimit limit = CouponUtil.parseDynamicLimitField(coupon);

            //判断是否可以使用
            if(limit == null || limit.isUsing(pricesParams)) {
                //可用
                canUserList.add(coupon);
            } else {
                //不可用
                noCanUserList.add(coupon);
            }
        }

        return resultList;
    }

    /**
     * 查询对应场次的优惠券列表
     * @param beginTime
     * @return
     */
    @Override
    @CacheUsing(key = "'coupons_' + #beginTime.getTime()")
    public List<Coupon> queryByTimes(Date beginTime) {
        QueryWrapper<Coupon> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("method", 1);
        queryWrapper.eq("go_start_time", beginTime);
        List<Coupon> coupons = couponDao.selectList(queryWrapper);
        return coupons;
    }

    /**
     * 扣减优惠券的库存
     * @param cid
     * @param uid
     * @return
     */
    @Override
    @Transactional
    public int updateCouponNumber(Integer cid, Integer uid) {
        //修改库存 - 线程安全的问题，实际开发应该还是直接写update SQL语句更安全
        Coupon coupon = couponDao.selectById(cid);
        coupon.setNumber(coupon.getNumber() - 1);
        couponDao.updateById(coupon);

        //新增领取记录
        CouponGet couponGet = new CouponGet()
                .setCid(cid)
                .setUid(uid)
                .setGetTime(new Date())
                .setGetType(0);

        couponGetService.save(couponGet);

        return 1;
    }
}